import { Node,Camera, view,screen, ResolutionPolicy, SafeArea, Layers, Widget, warn } from "cc";
import { LayerUI } from "./LayerUI";
import { LayerPopUp } from "./LayerPopUp";
import { LayerDialog } from "./LayerDialog";
import { LayerNotify } from "./LayerNotify";
import { hiyooo } from "../../HiYOOO";
import { UICallbacks } from "./Defines";
import { DelegateComponent } from "./DelegateComponent";

export enum LayerType{
    //二维游戏层
    Game = "LayerGame",
    //UI界面层
    UI= "LayerUI",
    //弹窗层
    PopUp="LayerPopUp",
    //模式弹窗层
    Dialog = "LayerDialog",
    //系统弹窗层
    System = "LayerSystem",
    //系统提示层
    Notify="LayerNotify",
    //新手引导层
    Guide="LayerGuide"
}

export interface UIConfig{
    /***/
    bundle?:string;
    //界面层级
    layer:LayerType;

    //prefab 路径 
    prefab:string;

    //是否自动释放
    destroy?:boolean;

    //是否非窗口区域关闭
    vacancy?:boolean;

    //是否展示mask
    mask?:boolean;

    //是否添加安全区域
    safeArea?:boolean;
}


export class LayerManager {
    /**界面根节点 */
    public root! : Node;

    /**摄像机 */
    public camera!: Camera;

    /**游戏节点 */
    public game!:Node;

    /**新手引导层 */
    public guide!:Node;

    /**窗口宽高比 */
    public windowAspectRatio:number = 0;

    /**设计宽高比 */
    public designAspectRatio:number = 0;

    /**是否开启手机安全区域适配 */
    public mobileSafeArea:boolean = false;


    // /**UI界面层 */
    private ui!:LayerUI;
    // /*** 弹窗层 */
    private popup!:LayerPopUp;
    // /*** 弹窗层 */
    private dialog!:LayerDialog;
    // /*** 系统弹窗层 */
    private system!:LayerDialog;
    // /**系统提示控制器，使用show方法显示*/
    private notify!:LayerNotify;
    // /**系统配置*/
    private configs:{[key:number]:UIConfig}={}


    /**
     * 初始化层级
     * @param node 
     */
    private initLayer(node:Node):void{
        this.root = node;
        this.initScreenAdapter();//初始化屏幕适配

        this.camera = this.root.getComponentInChildren(Camera)!;
        this.game = this.create_node(LayerType.Game);

        this.ui = new LayerUI(LayerType.UI);
        this.popup = new LayerPopUp(LayerType.PopUp);
        this.dialog = new LayerDialog(LayerType.Dialog);
        this.system = new LayerDialog(LayerType.System);
        this.notify = new LayerNotify(LayerType.Notify);
        this.guide = this.create_node(LayerType.Guide);
    }

    /**初始化屏幕适配 */
    private initScreenAdapter(){
        const drs = view.getDesignResolutionSize();//获取到设计分辨率
        const ws = screen.windowSize; //获取到屏幕实际尺寸

        this.windowAspectRatio = ws.width/ ws.height; //窗口的实际宽高比
        this.designAspectRatio = drs.width/drs.height;//设计的宽高比

        let finalW:number = 0; //最终width
        let finalH:number = 0; //最终height

        //屏幕宽高比 > 设计的宽高比，则说明 TODO:
        //TODO:这里没有搞明白 ，为什么实际的宽高比大于设计的宽高比就是横屏
        if (this.windowAspectRatio > this.designAspectRatio) {
            finalH = drs.height;
            finalW = finalH * ws.width / ws.height;
            hiyooo.log.logView("适配屏幕高度","【横屏】")
        }else{
            finalW = drs.width;
            finalH = finalW * ws.height / ws.width
            hiyooo.log.logView("适配屏幕宽度","【坚屏】")
        }
        //设置设计分辨率
        view.setDesignResolutionSize(finalW,finalH,ResolutionPolicy.UNKNOWN);

        //移动设备安全区域
        if (this.mobileSafeArea) {
            this.root.addComponent(SafeArea);
            hiyooo.log.logView("开启移动端安全区域")
        }

    }

    //初始化所有界面的配置对象
    public init(configs:{[key:number]:UIConfig}):void{
        this.configs = configs
    }

    /**
     * 设置窗口打开失败
     * @param callback 打开失败回调
     */
    setOpenFailure(callback:Function){
        this.ui.onOPenFailuer = this.popup.onOPenFailuer = this.dialog.onOPenFailuer = this.system.onOPenFailuer = callback;
    }

    /**
     * 打开等待
     */
    public waitOpen():void{
        this.notify.waitOpen();
    }

    /**
     * 关闭等待界面
     */
    public waitClose():void{
        this.notify.waitClose();
    }

    /**
     * 渐隐Toast
     * @param content 内容
     * @param useI18n 是否使用多语言,默认不使用
     */
    public toast(content:string,useI18n:boolean =false){
        this.notify.toast(content,useI18n);
    }

    /**
     * 同步打开一个界面
     * @param uiId 界面id
     * @param uiArags 界面参数
     * @param callback 回调
     */
    public open(uiId:number,uiArgs:any=null,callback?:UICallbacks):void{
        const config = this.configs[uiId];
        if (!config) {
            warn(`打开编号为：【${uiId}】界面失败，配置信息不存在`)
        }
        switch(config.layer){
            case LayerType.UI:
                this.ui.add(config,uiArgs,callback);
                break;
            case LayerType.Dialog:
                this.dialog.add(config,uiArgs,callback);
                break;
            case LayerType.PopUp:
                this.popup.add(config,uiArgs,callback);
                break;
            case LayerType.System:
                this.system.add(config,uiArgs,callback);
                break;
        }
    }

    /**
     * 异步打开一个界面 
     * @param uiId 界面的ID
     * @param uiArags 界面参数
     * @param callback 界面回调
     */
    public async openAsync(uiId:number,uiArgs:any = null):Promise<Node | null>{
        return new Promise<Node | null>((resolve,reject)=>{
            const callback:UICallbacks = {
                onAdded:(node:Node,params:any)=>{
                    resolve(node);
                },
                onLoadFailure:()=>{
                    resolve(null);
                }
            }
            this.open(uiId,uiArgs,callback);
        });
    }

    /**
     * 创建节点
     * @param name 节点名称 
     */
    private create_node(name:string):Node{
        //创建node
        const node  = new Node(name);
        //设置为Layer 为 2d
        node.layer = Layers.Enum.UI_2D;
        //设置widget 
        const widget : Widget = node.addComponent(Widget);
        //设置widget 的对齐方式 
        widget.isAlignLeft = widget.isAlignRight = widget.isAlignTop = widget.isAlignBottom = true;
        //设置widget 的对齐的值
        widget.left = widget.right = widget.top = widget.bottom = 0;
        /**
         *  ONCE = 0, 开启后会在 onEnable 时所在的那一帧结束前对齐一次，然后立刻禁用该 Widget。
            ALWAYS = 1, 始终保持对齐。
            ON_WINDOW_RESIZE = 2 一开始会像 ONCE 一样对齐一次，之后每当窗口大小改变时还会重新对齐。
         */
        widget.alignMode = 2;
        widget.enabled = true;
        return node;
    }


    /**
     * 替换界面
     * @param removeUiId  需要删除界面Id
     * @param openUiid 要打开的界面Id
     * @param uiArags 界面参数
     */
    public replace(removeUiId:number,openUiId:number,uiArgs:any = null):void{
        const callback :UICallbacks = {
            onAdded:(node:Node,params:any)=>{
                this.remove(removeUiId);
            },
        }
        this.open(openUiId,uiArgs,callback);
    }

   /**
    * 异步替换一个界面
    * @param removeUiId 需要删除的界面
    * @param openUiId 需要打开的界面
    * @param uiArgs 界面参数
    * @returns Node | null
    */
    public replaceAsync(removeUiId:number,openUiId,uiArgs:any =null):Promise<Node | null>{
        return new  Promise<Node | null>( async (resolve,reject)=>{
            const node  = await this.openAsync(openUiId,uiArgs);
            if (node) {
                this.remove(removeUiId);
                resolve(node);
            }else{
                resolve(null);
            }
        });
    }

    /**
     * 删除一个界面
     * @param uiId 界面唯一Id
     */
    public remove(uiId:number,isDestroy?:boolean):void{
        //查找配置中是否有此界面
        const config  = this.configs[uiId];
        if (config == null) {
            warn(`删除编号为【${uiId}】的界面失败，配置信息不存在`);
            return;    
        }
        switch (config.layer) {
            case LayerType.UI:
                this.ui.remove(config.prefab,isDestroy);
                break;
            case LayerType.Dialog:
                this.dialog.remove(config.prefab,isDestroy);
                break;
            case LayerType.PopUp:
                this.popup.remove(config.prefab,isDestroy);
                break;
            case LayerType.System:
                this.system.remove(config.prefab,isDestroy);
                break;
        }
    }
    
    /**
     * 缓存中是否有指定界面
     * @param uiId 界面唯一ID
     * @returns boolean
     */
    public has (uiId:number):boolean{
         
        const config  = this.configs[uiId];
        if (config == null) {
            warn(`编号为【${uiId}】的界面配置不存在，配置信息不存在`);
            return false;
        }
        let result  = false;
        switch (config.layer) {
            case LayerType.UI:
                result = this.ui.has(config.prefab);
                break;
            case LayerType.Dialog:
                result = this.dialog.has(config.prefab);
                break;
            case LayerType.PopUp:
                result = this.dialog.has(config.prefab);
                break;
            case LayerType.System:
                result = this.system.has(config.prefab);
                break;
        }
        return result;
    }

    /**
     * 根据指定Id获取已经打开的界面
     * @param uiId 界面唯一ID
     * @returns Node
     */
    public get(uiId:number):Node{
        const config  = this.configs[uiId];
        if (config == null) {
            return null!;
        }
        
        let result:Node  = null;

        switch (config.layer) {
            case LayerType.UI:
                result = this.ui.get(config.prefab);
                break;
            case LayerType.Dialog:
                result = this.dialog.get(config.prefab);
                break;
            case LayerType.PopUp:
                result = this.popup.get(config.prefab);
                break;
            case LayerType.System:
                result = this.system.get(config.prefab);
                break;
            default:
                break;
        }

        return result;

    }

    /**
     * 删除界面-通过ecs的this 添加进来的节点
     * @param node 界面节点
     * @param isDestroy 是否释放资源
     */
    public removeByNode(node:Node,isDestroy?:boolean){
        if (node instanceof Node) {
            let comp  = node.getComponent(DelegateComponent);
            if (comp && comp.vp) {
                if (node.parent) {
                    (node.parent as LayerUI).remove(comp.vp.config.prefab,isDestroy)
                }else if(isDestroy){
                    switch(comp.vp.config.layer){
                        case LayerType.UI:
                            //@ts-ignore
                            this.ui.removeCache(comp.vp.config.prefab);
                            break;
                        case LayerType.Dialog:
                            //@ts-ignore
                            this.dialog.removeCache(comp.vp.config.prefab);
                            break;
                        case LayerType.PopUp:
                            //@ts-ignore
                            this.popup.removeCaChe(comp.vp.config.prefab)
                            break;
                        case LayerType.System:
                            //@ts-ignore
                            this.system.removeCache(comp.vp.config.prefab)
                            break;
                    }
                }
            }else{
                warn(`当前删除的node不是通过界面管理器添加到舞台上`);
                node.destroy();
            }
        }
    }

    /**
     * 清除所有界面
     * @param isDestroy 是否释放资源
     */
    public clear(isDestroy:boolean = false){
        this.ui.clear(isDestroy);
        this.dialog.clear(isDestroy);
        this.popup.clear(isDestroy);
        this.system.clear(isDestroy);
    }


    
}